// dotenv.h - 支持分割key=value格式的环境变量库
#ifndef DOTENV_H
#define DOTENV_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <limits.h>

// 加载标志
#define DOTENV_PRESERVE 1   // 保留已存在的环境变量
#define DOTENV_SKIP_DUP 2   // 跳过重复的键

// 从默认.env文件加载环境变量
void dotenv_load(int flags);

// 从指定文件加载环境变量
void dotenv_load_from_file(const char* filename, int flags);

// 获取环境变量值（自动分割key=value格式，返回=右侧内容）
const char* dotenv_get(const char* name);

// 获取环境变量值，不存在则返回默认值
const char* dotenv_get_ordefault(const char* name, const char* default_value);

// 获取整数类型的环境变量值
int dotenv_get_as_int(const char* name, int default_value);

// 获取长整数类型的环境变量值
long dotenv_get_as_long(const char* name, long default_value);

// 获取布尔类型的环境变量值
bool dotenv_get_as_bool(const char* name, bool default_value);

// 获取字符串类型的环境变量值
const char* dotenv_get_as_string(const char* name, const char* default_value);

// 检查环境变量是否存在
bool dotenv_has(const char* name);

// 获取已加载的环境变量总数
size_t dotenv_count_vars(void);

// 迭代环境变量
bool dotenv_iter(size_t index, const char** key, const char** value);

// 打印指定键名
void dotenv_print_key(const char* name);

// 打印指定键的值
void dotenv_print_value(const char* name);

// 清除所有已加载的环境变量
void dotenv_clear(void);

#endif // DOTENV_H

#ifdef DOTENV_IMPLEMENTATION

// 内部数据结构
typedef struct dotenv_node {
    char* key;
    char* value;
    struct dotenv_node* next;
} dotenv_node_t;

typedef struct {
    dotenv_node_t** buckets;
    size_t capacity;
    size_t size;
} dotenv_hash_t;

static dotenv_hash_t* dotenv_hash = NULL;
static char* split_buffer = NULL;  // 用于存储分割后的临时值

// 跨平台设置环境变量
#if defined(_MSC_VER) || defined(__MINGW32__)
static int dotenv_setenv(const char* name, const char* value, int overwrite) {
    int errcode = 0;
    if (!overwrite) {
        size_t envsize = 0;
        errcode = getenv_s(&envsize, NULL, 0, name);
        if (errcode == 0 && envsize > 0) {
            return 0; // 变量已存在且不覆盖
        }
    }
    return _putenv_s(name, value);
}
#else
#define dotenv_setenv setenv
#endif

// 哈希函数
static unsigned int dotenv_hash_func(const char* key) {
    unsigned int hash = 5381;
    if (!key) return hash;
    for (size_t i = 0; key[i] != '\0'; i++) {
        hash = ((hash << 5) + hash) + (unsigned char)key[i];
    }
    return hash;
}

// 初始化哈希表
static void dotenv_hash_init(dotenv_hash_t* hash, size_t capacity) {
    hash->capacity = capacity;
    hash->size = 0;
    hash->buckets = (dotenv_node_t**)calloc(capacity, sizeof(dotenv_node_t*));
}

// 查找哈希表中的节点
static dotenv_node_t* dotenv_hash_find(dotenv_hash_t* hash, const char* key) {
    if (!hash || !hash->buckets || !key) return NULL;
    
    unsigned int index = dotenv_hash_func(key) % hash->capacity;
    dotenv_node_t* node = hash->buckets[index];
    
    while (node) {
        if (strcmp(node->key, key) == 0) {
            return node;
        }
        node = node->next;
    }
    
    return NULL;
}

// 添加节点到哈希表
static bool dotenv_hash_add(dotenv_hash_t* hash, const char* key, const char* value) {
    if (!hash || !key || !value) return false;
    if (dotenv_hash_find(hash, key)) return false;
    
    dotenv_node_t* node = (dotenv_node_t*)malloc(sizeof(dotenv_node_t));
    if (!node) return false;
    
    node->key = strdup(key);
    node->value = strdup(value);
    
    if (!node->key || !node->value) {
        free(node->key);
        free(node->value);
        free(node);
        return false;
    }
    
    unsigned int index = dotenv_hash_func(key) % hash->capacity;
    node->next = hash->buckets[index];
    hash->buckets[index] = node;
    hash->size++;
    
    return true;
}

// 更新哈希表中的节点
static bool dotenv_hash_update(dotenv_hash_t* hash, const char* key, const char* value) {
    if (!hash || !key || !value) return false;
    
    dotenv_node_t* node = dotenv_hash_find(hash, key);
    if (!node) return false;
    
    free(node->value);
    node->value = strdup(value);
    return node->value != NULL;
}

// 释放哈希表
static void dotenv_hash_free(dotenv_hash_t* hash) {
    if (!hash || !hash->buckets) return;
    
    for (size_t i = 0; i < hash->capacity; i++) {
        dotenv_node_t* node = hash->buckets[i];
        while (node) {
            dotenv_node_t* temp = node;
            node = node->next;
            
            // 清除环境变量
            #if defined(_MSC_VER) || defined(__MINGW32__)
            _putenv_s(temp->key, "");
            #else
            unsetenv(temp->key);
            #endif
            
            free(temp->key);
            free(temp->value);
            free(temp);
        }
    }
    
    free(hash->buckets);
    free(hash);
}

// 初始化内部存储
static void dotenv_init_storage(void) {
    if (!dotenv_hash) {
        dotenv_hash = (dotenv_hash_t*)malloc(sizeof(dotenv_hash_t));
        if (dotenv_hash) {
            dotenv_hash_init(dotenv_hash, 64);
        }
    }
    
    // 初始化分割缓冲区
    if (!split_buffer) {
        split_buffer = (char*)malloc(4096);  // 4KB缓冲区足够大多数场景
    }
}

// 修剪字符串
static char* dotenv_trim(char* str) {
    if (!str) return NULL;
    
    // 去除前导空白
    while (isspace((unsigned char)*str)) str++;
    
    // 空字符串处理
    if (*str == '\0') return str;
    
    // 去除尾随空白
    char* end = str + strlen(str) - 1;
    while (end >= str && isspace((unsigned char)*end)) end--;
    *(end + 1) = '\0';
    
    return str;
}

// 去除引号
static char* dotenv_strip_quotes(char* str) {
    if (!str) return NULL;
    
    size_t len = strlen(str);
    if (len < 2) return str;
    
    if ((str[0] == '"' && str[len-1] == '"') || 
        (str[0] == '\'' && str[len-1] == '\'')) {
        memmove(str, str + 1, len - 1);
        str[len - 2] = '\0';
    }
    
    return str;
}

// 分割key=value格式的字符串，返回=右侧的内容
static const char* dotenv_split_key_value(const char* str) {
    if (!str || !split_buffer) return str;
    
    // 复制到缓冲区避免修改原字符串
    strncpy(split_buffer, str, 4095);
    split_buffer[4095] = '\0';  // 确保终止
    
    // 查找第一个=
    char* eq_pos = strchr(split_buffer, '=');
    if (eq_pos) {
        return eq_pos + 1;  // 返回=右侧的内容
    }
    
    return split_buffer;  // 没有=则返回原始字符串
}

// 解析变量引用
static char* dotenv_resolve_vars(const char* value) {
    if (!value) return NULL;
    
    // 检查是否包含变量引用
    if (strchr(value, '$') == NULL) {
        return strdup(value);
    }
    
    size_t len = strlen(value);
    char* result = (char*)malloc(len * 2 + 1); // 分配足够的空间
    if (!result) return NULL;
    
    result[0] = '\0';
    size_t pos = 0;
    
    while (pos < len) {
        const char* dollar = strchr(value + pos, '$');
        if (!dollar) {
            // 复制剩余部分
            strcat(result, value + pos);
            break;
        }
        
        // 复制$之前的内容
        size_t before_len = dollar - (value + pos);
        if (before_len > 0) {
            char* before = (char*)malloc(before_len + 1);
            if (!before) {
                free(result);
                return NULL;
            }
            strncpy(before, value + pos, before_len);
            before[before_len] = '\0';
            strcat(result, before);
            free(before);
        }
        
        pos = dollar - value;
        
        // 处理${VAR}格式
        if (pos + 1 < len && value[pos + 1] == '{') {
            const char* closing = strchr(value + pos + 2, '}');
            if (!closing) {
                // 无效的引用格式，复制原始内容
                strncat(result, value + pos, len - pos);
                break;
            }
            
            // 提取变量名
            size_t var_len = closing - (value + pos + 2);
            char* var_name = (char*)malloc(var_len + 1);
            if (!var_name) {
                free(result);
                return NULL;
            }
            strncpy(var_name, value + pos + 2, var_len);
            var_name[var_len] = '\0';
            
            // 获取变量值（已分割处理）
            const char* var_value = dotenv_get(var_name);
            if (var_value) {
                strcat(result, var_value);
            } else {
                // 变量不存在，保留原始引用格式
                strncat(result, value + pos, closing - (value + pos) + 1);
            }
            
            free(var_name);
            pos = closing - value + 1;
        }
        // 处理$VAR格式
        else if (pos + 1 < len && 
                (isalnum((unsigned char)value[pos + 1]) || value[pos + 1] == '_')) {
            pos++; // 跳过$
            size_t var_start = pos;
            
            // 找到变量名的结束位置
            while (pos < len && 
                   (isalnum((unsigned char)value[pos]) || value[pos] == '_')) {
                pos++;
            }
            
            // 提取变量名
            size_t var_len = pos - var_start;
            char* var_name = (char*)malloc(var_len + 1);
            if (!var_name) {
                free(result);
                return NULL;
            }
            strncpy(var_name, value + var_start, var_len);
            var_name[var_len] = '\0';
            
            // 获取变量值（已分割处理）
            const char* var_value = dotenv_get(var_name);
            if (var_value) {
                strcat(result, var_value);
            } else {
                // 变量不存在，保留原始引用格式
                strncat(result, value + var_start - 1, pos - (var_start - 1));
            }
            
            free(var_name);
        }
        // 不是有效的变量引用，直接复制$
        else {
            strncat(result, value + pos, 1);
            pos++;
        }
    }
    
    // 调整内存大小
    return (char*)realloc(result, strlen(result) + 1);
}

// 从文件加载环境变量
void dotenv_load_from_file(const char* filename, int flags) {
    if (!filename) return;
    
    dotenv_init_storage();
    if (!dotenv_hash) return;
    
    FILE* file = fopen(filename, "r");
    if (!file) return;
    
    bool preserve = (flags & DOTENV_PRESERVE) != 0;
    bool skip_dup = (flags & DOTENV_SKIP_DUP) != 0;
    char line[1024];
    size_t line_num = 0;
    
    // 第一遍：加载所有基础变量
    while (fgets(line, sizeof(line), file)) {
        line_num++;
        size_t line_len = strlen(line);
        
        // 去除换行符
        if (line_len > 0 && line[line_len - 1] == '\n') {
            line[line_len - 1] = '\0';
            line_len--;
        }
        
        // 跳过空行和注释
        if (line_len == 0 || line[0] == '#') continue;
        
        // 查找等号
        char* eq_pos = strchr(line, '=');
        if (!eq_pos) {
            fprintf(stderr, "dotenv: 警告: 第 %zu 行没有等号，跳过\n", line_num);
            continue;
        }
        
        // 分割键和值
        *eq_pos = '\0'; // 临时分割
        char* key = dotenv_trim(line);
        
        // 跳过空键
        if (*key == '\0') {
            fprintf(stderr, "dotenv: 警告: 第 %zu 行键为空，跳过\n", line_num);
            *eq_pos = '=';
            continue;
        }
        
        // 处理值
        char* value = dotenv_trim(eq_pos + 1);
        *eq_pos = '='; // 恢复原字符
        value = dotenv_strip_quotes(value);
        
        // 检查是否已存在
        bool exists = dotenv_hash_find(dotenv_hash, key) != NULL;
        if (!exists) {
            // 检查系统环境变量中是否存在
            #if defined(_MSC_VER) || defined(__MINGW32__)
            size_t envsize = 0;
            int err = getenv_s(&envsize, NULL, 0, key);
            exists = (err == 0 && envsize > 0);
            #else
            exists = (getenv(key) != NULL);
            #endif
        }
        
        // 根据标志处理已存在的变量
        if (exists) {
            if (skip_dup || preserve) {
                continue;
            }
        }
        
        // 添加到内部存储并设置环境变量
        if (exists) {
            dotenv_hash_update(dotenv_hash, key, value);
        } else {
            dotenv_hash_add(dotenv_hash, key, value);
        }
        
        // 设置环境变量
        dotenv_setenv(key, value, !preserve);
    }
    
    // 第二遍：解析包含引用的变量
    rewind(file);
    line_num = 0;
    
    while (fgets(line, sizeof(line), file)) {
        line_num++;
        size_t line_len = strlen(line);
        
        if (line_len > 0 && line[line_len - 1] == '\n') {
            line[line_len - 1] = '\0';
            line_len--;
        }
        
        if (line_len == 0 || line[0] == '#') continue;
        
        char* eq_pos = strchr(line, '=');
        if (!eq_pos) continue;
        
        *eq_pos = '\0';
        char* key = dotenv_trim(line);
        if (*key == '\0') {
            *eq_pos = '=';
            continue;
        }
        
        // 只处理包含变量引用的行
        char* value = eq_pos + 1;
        if (strchr(value, '$') == NULL) {
            *eq_pos = '=';
            continue;
        }
        
        // 解析引用
        value = dotenv_trim(value);
        value = dotenv_strip_quotes(value);
        char* resolved_val = dotenv_resolve_vars(value);
        
        if (resolved_val) {
            // 更新内部存储和环境变量
            dotenv_hash_update(dotenv_hash, key, resolved_val);
            dotenv_setenv(key, resolved_val, 1);
            free(resolved_val);
        }
        
        *eq_pos = '=';
    }
    
    fclose(file);
}

// 从默认.env文件加载
void dotenv_load(int flags) {
    dotenv_load_from_file(".env", flags);
}

// 获取环境变量值（核心修复：分割key=value格式，只返回=右侧内容）
const char* dotenv_get(const char* name) {
    if (!name || !split_buffer) return NULL;
    
    // 先从系统环境变量获取
    const char* env_val = getenv(name);
    if (!env_val) return NULL;
    
    // 分割key=value格式，返回=右侧的内容
    return dotenv_split_key_value(env_val);
}

// 获取环境变量值，带默认值
const char* dotenv_get_ordefault(const char* name, const char* default_value) {
    const char* val = dotenv_get(name);
    return val ? val : default_value;
}

// 获取整数类型的环境变量值
int dotenv_get_as_int(const char* name, int default_value) {
    const char* val = dotenv_get(name);
    if (!val) return default_value;
    
    char* endptr;
    long num = strtol(val, &endptr, 10);
    
    // 检查转换是否成功
    if (endptr == val || *endptr != '\0') {
        return default_value;
    }
    
    // 检查是否在int范围内
    if (num < INT_MIN || num > INT_MAX) {
        return default_value;
    }
    
    return (int)num;
}

// 获取长整数类型的环境变量值
long dotenv_get_as_long(const char* name, long default_value) {
    const char* val = dotenv_get(name);
    if (!val) return default_value;
    
    char* endptr;
    long num = strtol(val, &endptr, 10);
    
    // 检查转换是否成功
    if (endptr == val || *endptr != '\0') {
        return default_value;
    }
    
    return num;
}

// 获取布尔类型的环境变量值
bool dotenv_get_as_bool(const char* name, bool default_value) {
    const char* val = dotenv_get(name);
    if (!val) return default_value;
    
    // 处理常见的布尔值表示
    if (strcmp(val, "true") == 0 || strcmp(val, "1") == 0 || 
        strcmp(val, "yes") == 0 || strcmp(val, "on") == 0) {
        return true;
    }
    
    if (strcmp(val, "false") == 0 || strcmp(val, "0") == 0 || 
        strcmp(val, "no") == 0 || strcmp(val, "off") == 0) {
        return false;
    }
    
    return default_value;
}

// 获取字符串类型的环境变量值
const char* dotenv_get_as_string(const char* name, const char* default_value) {
    return dotenv_get_ordefault(name, default_value);
}

// 检查环境变量是否存在
bool dotenv_has(const char* name) {
    return dotenv_get(name) != NULL;
}

// 获取变量总数
size_t dotenv_count_vars(void) {
    return dotenv_hash ? dotenv_hash->size : 0;
}

// 迭代变量
// 迭代变量（确保key是=左侧，value是=右侧）
bool dotenv_iter(size_t index, const char** key, const char** value) {
    if (!dotenv_hash || !key || !value || index >= dotenv_hash->size) {
        return false;
    }

    // 用于分割处理的临时缓冲区
    static char key_buf[1024];
    static char val_buf[4096];

    size_t found = 0;
    for (size_t i = 0; i < dotenv_hash->capacity; i++) {
        dotenv_node_t* node = dotenv_hash->buckets[i];
        while (node) {
            if (found == index) {
                // 处理key：确保只包含=左侧内容
                char* eq_pos = strchr(node->key, '=');
                if (eq_pos) {
                    size_t key_len = eq_pos - node->key;
                    if (key_len >= sizeof(key_buf)) key_len = sizeof(key_buf) - 1;
                    strncpy(key_buf, node->key, key_len);
                    key_buf[key_len] = '\0';
                    *key = key_buf;
                } else {
                    *key = node->key;  // 无=则使用原始key
                }

                // 处理value：确保只包含=右侧内容
                eq_pos = strchr(node->value, '=');
                if (eq_pos) {
                    size_t val_len = strlen(eq_pos + 1);
                    if (val_len >= sizeof(val_buf)) val_len = sizeof(val_buf) - 1;
                    strncpy(val_buf, eq_pos + 1, val_len);
                    val_buf[val_len] = '\0';
                    *value = val_buf;
                } else {
                    *value = node->value;  // 无=则使用原始value
                }

                return true;
            }
            found++;
            node = node->next;
        }
    }

    return false;
}

// 打印指定键名
void dotenv_print_key(const char* name) {
    if (!name) return;
    printf("%s\n", name);
}

// 打印指定键的值
void dotenv_print_value(const char* name) {
    if (!name) return;
    const char* val = dotenv_get(name);
    printf("%s\n", val ? val : "(null)");
}

// 清除所有变量
void dotenv_clear(void) {
    if (dotenv_hash) {
        dotenv_hash_free(dotenv_hash);
        dotenv_hash = NULL;
    }
    
    // 释放分割缓冲区
    if (split_buffer) {
        free(split_buffer);
        split_buffer = NULL;
    }
}

#endif // DOTENV_IMPLEMENTATION